#ifndef PRIMITIVE_H
#define PRIMITIVE_H

#include "glm/glm.hpp"

#include "collision.h"
#include "frame.h"

#include <QSharedPointer>

// TODO: define more primitives
typedef enum {BoxPrimitive, SpherePrimitive, CylinderPrimitive} PrimitiveType;

using namespace Collision;

class Primitive {
public:
    Primitive(PrimitiveType type);
    // Verifies the collision state between two primitives
    virtual CollisionState doCollide(Primitive &) = 0;
    // Tells if a point is inside this primitive, useful for full collision testing
    virtual bool inside(const glm::vec4  &) = 0;
    const PrimitiveType type;

//    // Returns a matrix that transforms from local coord system to world coord system
//    // Column major matrix
//    virtual glm::mat4x4 getToWorldMatrix();
//    // Returns a matrix that transforms from world coord system to local coord system
//    // Column major matrix
//    virtual glm::mat4x4 getToLocalMatrix();

//    void rotateX(float angle);
//    void rotateY(float angle);
//    void rotateZ(float angle);

//    void translate( glm::vec4  );
//    void translate( float x, float y, float z );
    QSharedPointer<Frame> m_frame;
//    void scale(float x, float y, float z);
//    void scale( glm::vec4 );

//    bool update_matrix;
//    // TODO: object orientation
//    glm::vec4  scaleFactors;    // 0 = scale_x, 1 = scale_y, 2 = scale_z
//    glm::vec4  rotate;   // 0 = angle_x, 1 = angle_y, 2 = angle_z
//    glm::vec4  origin;   // origin

//    glm::mat4x4 local;
//    glm::mat4 localScale;
//    glm::mat4x4 world;
//    glm::mat4 worldScale;
};

class Box : public Primitive {
public:
    // Central point plus the cube sides
    Box(const glm::vec4  &origin, float side);
    CollisionState doCollide(Primitive &);
    bool inside(const glm::vec4  &);

    glm::vec4  m_origin;   // origin
    float m_side;
    glm::vec4  m_points[8]; // top-right-front, top-left-front, bottom-left-front,bottom-right-front... the same ordering for back
    unsigned int m_vbo_id;
    unsigned int m_index_vbo;
};

class Sphere : public Primitive {
public:
    Sphere(const glm::vec4  &origin, float radius);
    CollisionState doCollide(Primitive &) ;
    bool inside(const glm::vec4  &);

    glm::vec4  m_origin;   // origin
    float m_radius;
    int num_vertices;
    unsigned int m_vbo_id;
    unsigned int m_index_vbo;
};

#endif // PRIMITIVE_H
